import logging
from datetime import timedelta
from typing import Optional

from jose import JWTError, jwt
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.config import settings
from app.db.session import AsyncSessionLocal
from app.models.user import User
from app.schemas.token import TokenData
from app.security.utils import verify_password, create_access_token, create_refresh_token

# 配置日志
logger = logging.getLogger(__name__)


class AuthService:
    """
    认证服务类，处理用户认证相关的业务逻辑
    """
    
    async def get_user(self, login_name: str, tenant_id: str) -> Optional[User]:
        """
        根据登录名和租户ID获取用户
        """
        async with AsyncSessionLocal() as db:
            result = await db.execute(select(User).where(User.login_name == login_name, User.tenant_id == tenant_id))
            user = result.scalar_one_or_none()
            return user
    
    async def authenticate_user(self, login_name: str, password: str, tenant_id: str) -> Optional[User]:
        """
        验证用户凭据和租户ID
        """
        logger.debug(f"验证用户凭据: {login_name}, 租户ID: {tenant_id}")
        user = await self.get_user(login_name, tenant_id)
        if not user:
            logger.warning(f"用户不存在: {login_name}, 租户ID: {tenant_id}")
            return None
        if not verify_password(password, user.hashed_password):
            logger.warning(f"用户密码验证失败: {login_name}, 租户ID: {tenant_id}")
            return None
        if user.tenant_id != tenant_id:
            logger.warning(f"租户ID不匹配: {login_name}, 租户ID: {tenant_id}, 实际: {user.tenant_id}")  
            return None
        logger.debug(f"用户认证成功: {login_name}, 租户ID: {tenant_id}")
        return user
    
    async def get_current_user_from_token(self, token: str) -> Optional[User]:
        """
        从令牌中获取当前用户
        """
        logger.debug(f"开始解析认证令牌: {token}")

        try:
            payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
            logger.debug(f"令牌解码成功，载荷: {payload}")

            login_name: str = payload.get("loginName")
            if login_name is None:
                logger.warning("令牌中没有找到登录名")
                return None
            full_name: str = payload.get("fullName")
            tenant_id: str = payload.get("tenantId")
            if tenant_id is None:
                logger.warning("令牌中没有找到租户ID")
                return None
            token_data = TokenData(login_name=login_name, full_name=full_name, tenant_id=tenant_id)
            logger.debug(f"从令牌中提取登录名: {login_name}")
        except JWTError as e:
            logger.error(f"令牌解码失败: {e}")
            return None
        
        user = await self.get_user(login_name=token_data.login_name, tenant_id=token_data.tenant_id)
        if user is None:
            logger.warning(f"令牌中的用户不存在: {token_data.login_name}")
            return None
        
        logger.debug(f"token中的用户: {user.login_name}")
        return user
    
    def create_access_token(self, login_name: str, full_name: str , tenant_id: str) -> str:
        """
        创建访问令牌，包含login_name, full_name和tenant_id
        """
        access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
        token_data = {
            "loginName": login_name,
            "fullName": full_name,
            "tenantId": tenant_id
        }
        access_token = create_access_token(
            data=token_data, expires_delta=access_token_expires
        )
        return access_token
    
    def create_refresh_token(self, login_name: str, full_name: str, tenant_id: str) -> str:
        """
        创建刷新令牌
        """
        refresh_token = create_refresh_token(
            data={"loginName": login_name, "fullName": full_name, "tenantId": tenant_id}
        )
        return refresh_token
    
    def verify_refresh_token(self, token: str) -> Optional[TokenData]:
        """
        验证刷新令牌并返回用户登录名
        """
        try:
            payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
            is_refresh: bool = payload.get("refresh", False)
            login_name: str = payload.get("loginName")
            full_name: str = payload.get("fullName")
            tenant_id: str = payload.get("tenantId")
            if not login_name or not is_refresh:
                logger.warning("无效的刷新令牌")
                return None
            return TokenData(login_name=login_name, full_name=full_name, tenant_id=tenant_id)
        except JWTError as e:
            logger.error(f"刷新令牌验证失败: {e}")
            return None


# 创建全局认证服务实例
auth_service = AuthService()